// Copyright (C) 2003 IFOnlyRT Project.

// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License 2.0 for more details.

// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/

// Official SVN repository and contact information can be found at
// http://code.google.com/p/ifonlyrt/


/*
 * CVector3.cpp
 *
 *  Created on: 15 oct. 2009
 *      Author: Maxime Gaudin
 */

#include <math.h>

#include "CVector3.hpp"

template <typename T> const CVector3<T> CVector3<T>::Zero		(0, 0, 0);
template <typename T> const CVector3<T> CVector3<T>::One		(1, 1, 1);
template <typename T> const CVector3<T> CVector3<T>::Up			(0, 1, 0);
template <typename T> const CVector3<T> CVector3<T>::Down		(0, -1, 0);
template <typename T> const CVector3<T> CVector3<T>::Right		(1, 0, 0);
template <typename T> const CVector3<T> CVector3<T>::Left		(-1, 0, 0);
template <typename T> const CVector3<T> CVector3<T>::Backward	(0, 0, 1);
template <typename T> const CVector3<T> CVector3<T>::Forward	(0, 0, -1);

// Constructeurs & Destructeur ==============================
template <typename T>
CVector3<T>::CVector3()
: X(T())
, Y(T())
, Z(T())
{ NumbersOnly<T> isNumeric;	}

template <typename T>
CVector3<T>::CVector3(const CVector3<T>& Copy)
: X(Copy.X)
, Y(Copy.Y)
, Z(Copy.Z)
{ NumbersOnly<T> isNumeric;	}

template<typename T>
CVector3<T>::CVector3(const T& vX, const T& vY, const T& vZ)
: X(vX)
, Y(vY)
, Z(vZ)
{ NumbersOnly<T> isNumeric;	}

template<typename T>
CVector3<T>::CVector3(const T& Value)
: X(Value)
, Y(Value)
, Z(Value)
{ NumbersOnly<T> isNumeric;	}
// ==========================================================

// Méthodes publiques =======================================================================
template<typename T>
T CVector3<T>::GetModulus() const
{
	return static_cast<T>(sqrt(X * X + Y * Y + Z * Z));
}

template<typename T>
T CVector3<T>::GetSquaredModulus() const
{
	return X * X + Y * Y + Z * Z;
}

template<typename T>
void CVector3<T>::Normalize()
{
	double modulus = GetModulus();

	if(modulus != 0)
	{
		X /= modulus;
		Y /= modulus;
		Z /= modulus;
	}
}

template<typename T>
CVector3<T> CVector3<T>::GetNormalized() const
{
	T modulus = GetModulus();
	return (modulus != 0) ? CVector3<T>(X / modulus, Y / modulus, Z / modulus) : CVector3<T>::Zero;
}
// ==========================================================================================

// Opérateurs ========================================================================
template<typename T>
T CVector3<T>::operator [](const uint i)
{
	switch(i)
	{
	case(0):
			return X;
	case(1):
			return Y;
	case(2):
			return Z;
	}
}

template<typename T>
CVector3<T> CVector3<T>::operator =(const CVector3<T>& V2)
{
	if(this != &V2)
	{
		X = V2.X;
		Y = V2.Y;
		Z = V2.Z;

		return *this;
	}

	return V2;
}

template<typename T>
CVector3<T> CVector3<T>::operator +(const CVector3<T>& V2)
{ return CVector3(X + V2.X, Y + V2.Y, Z + V2.Z); }

template<typename T>
CVector3<T> CVector3<T>::operator +=(const CVector3<T>& V2)
{
	X += V2.X;
	Y += V2.Y;
	Z += V2.Z;

	return (*this);
}

template<typename T>
CVector3<T> CVector3<T>::operator -(const CVector3<T>& V2)
{ return CVector3(X - V2.X, Y - V2.Y, Z - V2.Z); }

template<typename T>
CVector3<T> CVector3<T>::operator -=(const CVector3<T>& V2)
{
	X -= V2.X;
	Y -= V2.Y;
	Z -= V2.Z;

	return (*this);
}

template<typename T>
CVector3<T> CVector3<T>::operator *(const T Scalar)
{ return CVector3(X * Scalar, Y * Scalar, Z * Scalar); }

template<typename T>
CVector3<T> CVector3<T>::operator *=(const T Scalar)
{
	X *= Scalar;
	Y *= Scalar;
	Z *= Scalar;

	return (*this);
}

template<typename T>
CVector3<T> CVector3<T>::operator /(const T Scalar)
{ return (Scalar != 0) ? CVector3(X / Scalar, Y / Scalar, Z / Scalar) : *this; }

template<typename T>
CVector3<T> CVector3<T>::operator /=(const T Scalar)
{
	X /= Scalar;
	Y /= Scalar;
	Z /= Scalar;

	return (*this);
}
// ====================================================================================
